package com.pig4cloud.pig.auth.endpoint;

import cn.hutool.core.lang.Validator;
import com.pig4cloud.captcha.ArithmeticCaptcha;
import com.pig4cloud.pig.common.core.constant.CacheConstants;
import com.pig4cloud.pig.common.core.constant.SecurityConstants;
import com.pig4cloud.pig.common.core.util.RedisUtils;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

/**
 * 图形验证码生成端点
 * <p>
 * 提供图形验证码的生成和输出功能，用于防止暴力破解和机器人攻击
 * 使用算术验证码（加减法运算），用户需要计算结果才能通过验证
 * 验证码结果存储在 Redis 中，有效期为 60 秒
 *
 * @author lengleng
 * @date 2022/6/27
 */
@RestController
@RequestMapping("/code")  // 验证码相关接口的基础路径
@RequiredArgsConstructor
public class ImageCodeEndpoint {

	/**
	 * 验证码图片默认宽度（像素）
	 */
	private static final Integer DEFAULT_IMAGE_WIDTH = 100;

	/**
	 * 验证码图片默认高度（像素）
	 */
	private static final Integer DEFAULT_IMAGE_HEIGHT = 40;

	/**
	 * 生成图形验证码并输出到响应流
	 * <p>
	 * 功能说明：
	 * 1. 生成算术验证码（如：2+3=?）
	 * 2. 将计算结果存储到 Redis，键为：code_key:随机字符串
	 * 3. 将验证码图片直接输出到 HTTP 响应流
	 * 
	 * 安全策略：
	 * - 不接受手机号作为随机字符串，防止利用验证码进行短信轰炸
	 * - 验证码 60 秒后自动过期
	 * 
	 * @param randomStr 随机字符串，用于标识和缓存验证码，由前端生成
	 * @param response HTTP 响应对象，用于输出验证码图片流
	 */
	@SneakyThrows  // 自动处理受检异常，主要是 IOException
	@GetMapping("/image")  // GET 请求，路径为 /code/image
	public void image(String randomStr, HttpServletResponse response) {
		// 创建算术验证码对象，设置图片尺寸
		ArithmeticCaptcha captcha = new ArithmeticCaptcha(DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT);

		// 安全校验：如果随机字符串是手机号格式，拒绝生成验证码
		// 防止恶意用户使用手机号作为 key 进行短信轰炸
		if (Validator.isMobile(randomStr)) {
			return;
		}

		// 获取验证码的计算结果
		String result = captcha.text();
		// 将结果存储到 Redis，键格式：code_key:randomStr，有效期 60 秒
		RedisUtils.set(CacheConstants.DEFAULT_CODE_KEY + randomStr, result, SecurityConstants.CODE_TIME,
				TimeUnit.SECONDS);
		// 将验证码图片直接输出到响应流，前端可直接显示
		captcha.out(response.getOutputStream());
	}

}
